__author__ = "Gonzalo Castillo"
__date__ = "$28-nov-2010 20:33:45$"

import antlr3

# Valores por default
posXInicial = 0.0
posYInicial = 0.0
escalaInicial = 1.0
anchoInicial = 0.0
alturaSupInicial = 0.0
alturaInfInicial = 0.0

# Constantes
ANCHO_LETRA = 0.6
ALTO_LETRA = 1.0
ESCALA_INDICE = 0.7
DESPLAZAMIENTO_SUPERIOR = 0.45
DESPLAZAMIENTO_INFERIOR = -0.25
SOLAPAMIENTO_INDICE = 0.5
ANCHO_DE_RAYA = 0.1
DESPLAZAMIENTO_DE_RAYA = 0.28
ANCHO_PARENTESIS = 0.6
DIBUJAR_RECUADROS = False
DIBUJAR_SEPARACION_ALTURAS = False

# Esta clase sirve para definir nuevos atributos a los nodos
class ArbolConAtributos(antlr3.tree.CommonTree):
    def __init__(self, payload):
	antlr3.tree.CommonTree.__init__(self, payload)
	self.posX = posXInicial #heredado
	self.posY = posYInicial #heredado
	self.escala = escalaInicial #heredado
	self.ancho = anchoInicial   #sintetizado
	self.alturaSuperior = alturaSupInicial #sintetizado
	self.alturaInferior = alturaInfInicial #sintetizado
        self.archivo = ""
    
    # Arma lineas para el archivo .ps
    def armarLineaPS(self, posX, posY, scale1, scale2, char):
	return 'gsave %f %f moveto %f %f scale (%s) show grestore\n' %(posX, posY, scale1, scale2, char)

    # devuelve la linea para recuadrar el nodo
    def dibujarRecuadro(self):
        recuadro = "gsave newpath %f %f moveto %f %f lineto %f %f lineto %f %f lineto %f %f lineto 0.0001 setlinewidth stroke grestore\n" %(self.posX, self.posY, self.posX+self.ancho, self.posY, self.posX+self.ancho ,self.posY+self.altura(),self.posX ,self.posY+self.altura(), self.posX, self.posY )
        if (DIBUJAR_SEPARACION_ALTURAS):
            recuadro += "gsave newpath %f %f moveto %f %f lineto 0.0001 setlinewidth stroke grestore\n" %(self.posX , self.posY + self.alturaInferior, self.posX+self.ancho, self.posY + + self.alturaInferior)
        return recuadro

    # Muestra un nodo y sus atributos 	
    def showNode(self):
        string = self.text + " x:" + str(self.posX) + " y:" + str(self.posY) + " e:" + str(self.escala)
        string += " altura:" + str(self.altura()) + " altS: " + str(self.alturaSuperior) + " altI: " + str(self.alturaInferior) + " ancho: " + str(self.ancho)
        return string
    
    # Muestra un arbol sintactico
    def showArbol(self, tabs):
        tab = ""
        for i in xrange(0, tabs):
            tab = tab + "\t"
        if self.getChildCount() == 0:
            print tab + "HOJA:  " + self.showNode()
        else:
            print tab + "NODO:" + self.showNode()
            for i in xrange(0, self.getChildCount()):
                self.getChild(i).showArbol(tabs + 1)
    
    # Devuelve la altura total de un nodo 
    def altura(self):
        return self.alturaInferior + self.alturaSuperior

    # Setea la escala, la altura inferior, la altura superior, y el ancho de un nodo 
    def setAtributos(self, escala):
        self.escala = escala
        if self.text == "EXPRESION":
            hijo = self.getChild(0) # la expresion tiene un unico hijo
            hijo.setAtributos(self.escala)

            self.ancho = hijo.ancho

            self.alturaInferior = hijo.alturaInferior
            self.alturaSuperior = hijo.alturaSuperior

        elif self.text == "DIV":
            dividendo = self.getChild(0)
            divisor = self.getChild(1)
            dividendo.setAtributos(self.escala)
            divisor.setAtributos(self.escala)

            self.ancho = max(divisor.ancho, dividendo.ancho)

            self.alturaSuperior = dividendo.altura() + DESPLAZAMIENTO_DE_RAYA * self.escala
            self.alturaInferior = divisor.altura() - DESPLAZAMIENTO_DE_RAYA * self.escala

        elif self.text == "CONC":

            for i in xrange(0, self.getChildCount()):
                hijo = self.getChild(i)
                hijo.setAtributos(self.escala)

                self.ancho += hijo.ancho

                self.alturaSuperior = max(self.alturaSuperior, hijo.alturaSuperior)
                self.alturaInferior = max(self.alturaInferior, hijo.alturaInferior)

        elif self.text == "SUB":
            valor = self.getChild(0)
            valor.setAtributos(self.escala)
            self.ancho = valor.ancho
            subindice = self.getChild(1) #este esta definido siempre en sub
            subindice.setAtributos(ESCALA_INDICE * self.escala)
            if (subindice.altura() <= valor.altura): #=> sub.h/2 <= v.h/2
                self.alturaInferior = subindice.altura() * 0.5 + valor.alturaInferior
            else:
                self.alturaInferior = subindice.altura() - valor.altura() * 0.5 + valor.alturaInferior

            if (self.getChildCount() == 3):
                superindice = self.getChild(2)
                superindice.setAtributos(ESCALA_INDICE * self.escala)
                self.ancho += max(subindice.ancho, superindice.ancho)
                if (superindice.altura() <= valor.altura()):
                    self.alturaSuperior = valor.alturaSuperior + superindice.altura() * 0.5
                else:
                    self.alturaSuperior = valor.altura() * 0.5 + superindice.altura()
            else:
                self.ancho += subindice.ancho
                self.alturaSuperior = valor.alturaSuperior

	elif self.text == "SUP":
            valor = self.getChild(0)
            valor.setAtributos(self.escala)
            self.ancho = valor.ancho

            superindice = self.getChild(1)
            superindice.setAtributos(ESCALA_INDICE * self.escala)
            if (superindice.altura() <= valor.altura()):
                self.alturaSuperior = valor.alturaSuperior + superindice.altura() * 0.5
            else:
                self.alturaSuperior = valor.altura() * 0.5 + superindice.altura()

            if (self.getChildCount() == 3): # hay subindice
                subindice = self.getChild(2)
                subindice.setAtributos(ESCALA_INDICE * self.escala)
                self.ancho += max(subindice.ancho, superindice.ancho)
                if (subindice.altura() <= valor.altura): #=> sub.h/2 <= v.h/2
                    self.alturaInferior = subindice.altura() * 0.5 + valor.alturaInferior
                else:
                    self.alturaInferior = subindice.altura() - valor.altura() * 0.5 + valor.alturaInferior

            else:
                self.ancho += superindice.ancho
                self.alturaInferior = valor.alturaInferior

        elif self.text == "PARENTESIS":
            hijo = self.getChild(0)
            hijo.setAtributos(self.escala)
            # los parentesis tienen que medir tanto como la expresion interna
            # entonces el ancho de los mismos va a ser el ancho de la letra * la altura de la expresion de adentro
            self.alturaSuperior = hijo.alturaSuperior
            self.alturaInferior = hijo.alturaInferior
            self.ancho = hijo.ancho + 2 * self.escala * ANCHO_PARENTESIS 

        else: #atomo
            self.ancho = ANCHO_LETRA * escala
            self.alturaSuperior = ALTO_LETRA * escala * 0.8
            self.alturaInferior = ALTO_LETRA * escala * 0.2
    
    # Setea las posiciones de un nodo devolviendo las lineas correspondientes al archivo .ps
    def setPosiciones(self, posX, posY):
        self.posX = posX
	self.posY = posY
        
	if self.text == "EXPRESION":
            hijo = self.getChild(0) # la expresion tiene unico hijo
	    hijo.setPosiciones(self.posX, self.posY)
            self.archivo = hijo.archivo
            if (DIBUJAR_RECUADROS):
                self.archivo += self.dibujarRecuadro()

	elif self.text == "DIV":
            pass
            dividendo = self.getChild(0)
            divisor = self.getChild(1)
	    
	    if dividendo.ancho > divisor.ancho:
		posicionCentrada = self.posX + (dividendo.ancho - divisor.ancho) / 2.0
		dividendo.setPosiciones(self.posX, self.posY +  self.altura() - dividendo.altura())
		divisor.setPosiciones(posicionCentrada, self.posY)
	    else:
		posicionCentrada = self.posX + (divisor.ancho - dividendo.ancho) / 2.0
		dividendo.setPosiciones(posicionCentrada, self.posY + self.altura() - dividendo.altura())
		divisor.setPosiciones(self.posX, self.posY)

	    maxAncho = max(divisor.ancho, dividendo.ancho)
	    
	    self.archivo = dividendo.archivo
	    self.archivo+= 'gsave %f %f moveto %f %f rlineto stroke grestore\n' %(self.posX , self.posY + self.alturaInferior + DESPLAZAMIENTO_DE_RAYA * self.escala , maxAncho, 0.0)
	    self.archivo+= divisor.archivo
	    
	    if (DIBUJAR_RECUADROS):
                self.archivo += self.dibujarRecuadro()

        elif self.text == "CONC":
            desplazamiento = self.posX
	    for i in xrange(0, self.getChildCount()):
                hijo = self.getChild(i)
                hijo.setPosiciones(desplazamiento, self.posY + self.alturaInferior - hijo.alturaInferior)
		desplazamiento += hijo.ancho
                self.archivo += hijo.archivo
            
            if (DIBUJAR_RECUADROS):
                self.archivo += self.dibujarRecuadro()

        elif self.text == "SUB":
            valor = self.getChild(0)
            valor.setPosiciones(self.posX, self.posY+ self.alturaInferior - valor.alturaInferior)
            self.archivo += valor.archivo

            subindice = self.getChild(1) #este esta definido siempre en sub
            subindice.setPosiciones(self.posX+valor.ancho, self.posY)
            self.archivo += subindice.archivo

            if (self.getChildCount() == 3):
                superindice = self.getChild(2)
                if(superindice.altura() <= valor.altura()):
                    superindice.setPosiciones(self.posX+valor.ancho, valor.posY+valor.altura() - superindice.altura() * 0.5)
                else:
                    superindice.setPosiciones(self.posX+valor.ancho, valor.posY+valor.altura()  * 0.5)
                self.archivo += superindice.archivo

            if (DIBUJAR_RECUADROS):
                self.archivo += self.dibujarRecuadro()

        elif self.text == "SUP":
            valor = self.getChild(0)
            valor.setPosiciones(self.posX, self.posY+ self.alturaInferior - valor.alturaInferior)
            self.archivo += valor.archivo
            superindice = self.getChild(1)
            # seteo la posicion del valor de acuerdo a si hay o no subindice
            if (self.getChildCount() == 3):
                subindice = self.getChild(2)
                subindice.setPosiciones(self.posX+valor.ancho, self.posY)
                self.archivo += subindice.archivo

            # seteo la posicion del superindice de acuerdo a la posicion del valor
            if(superindice.altura() <= valor.altura()):
                superindice.setPosiciones(self.posX+valor.ancho, valor.posY+valor.altura() - superindice.altura() * 0.5)
            else:
                superindice.setPosiciones(self.posX+valor.ancho, valor.posY+valor.altura()  * 0.5)

            self.archivo += superindice.archivo

            if (DIBUJAR_RECUADROS):
                self.archivo += self.dibujarRecuadro()
		
        elif self.text == "PARENTESIS":
            hijo = self.getChild(0) # el parentesis tiene unico hijo
            anchoParententesis = self.escala * ANCHO_PARENTESIS 
            hijo.setPosiciones(self.posX + anchoParententesis , self.posY)

            self.archivo += self.armarLineaPS(self.posX, self.posY + 0.25 * self.altura(), self.escala, self.altura(), "\\(" )
            self.archivo += hijo.archivo
            self.archivo += self.armarLineaPS(self.posX + anchoParententesis + hijo.ancho, self.posY + 0.25 * self.altura(), self.escala, self.altura(), "\\)" )

            if (DIBUJAR_RECUADROS):
                self.archivo += self.dibujarRecuadro()

        else: #atomo
            self.archivo = self.armarLineaPS(self.posX, self.posY+self.alturaInferior, self.escala, self.escala, self.text)
            if (DIBUJAR_RECUADROS):
                self.archivo += self.dibujarRecuadro()



# Esta clase sirve para que al momento de crear un nodo se cree un nodo con atributos
class adaptor(antlr3.tree.CommonTreeAdaptor):
    def createWithPayload(self, payload):
        return ArbolConAtributos(payload)